﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Krilib.Control.Base;
using System.Drawing;
using System.Windows.Forms;

namespace Krile.Forms.MainForm.Controls.Timeline
{
    internal class TimelineMouseManager : IDisposable
    {
        TimelineList linkedList;
        private object itemsLocker = new object();
        TimelineMouseControllableItem[] Items;
        TimelineMouseControllableItem lastPointed;
        ToolTip toolTip;

        public TimelineMouseManager(TimelineList linked)
        {
            linkedList = linked;
            //initialize
            lastPointed = null;
            toolTip = new ToolTip();
            toolTip.ShowAlways = true;
            toolTip.Active = false;
            lock (itemsLocker)
                Items = linkedList.MouseItems;
            //events set
            linkedList.MouseLeave += new EventHandler(linkedList_MouseLeave);
            linkedList.MouseMove += new MouseEventHandler(linkedList_MouseMove);
            linkedList.MouseClick += new MouseEventHandler(linkedList_MouseClick);
            linkedList.MouseDoubleClick += new MouseEventHandler(linkedList_MouseDoubleClick);
            linkedList.MouseUp += new MouseEventHandler(linkedList_MouseUp);
            linkedList.MouseDown += new MouseEventHandler(linkedList_MouseDown);
            linkedList.TimelineMouseControllableItemsUpdated += new EventHandler(linkedList_TimelineMouseControllableItemsUpdated);
        }

        void linkedList_MouseDown(object sender, MouseEventArgs e)
        {
            ChainedMouseEventArgs xe = ChainedMouseEventArgs.Factory(e);
            foreach (var tmci in GetItemByPoint(e.Location))
            {
                tmci.OnMouseDown(sender, xe);
                if (xe.Trapped) break;
            }
        }

        void linkedList_MouseUp(object sender, MouseEventArgs e)
        {
            ChainedMouseEventArgs xe = ChainedMouseEventArgs.Factory(e);
            foreach (var tmci in GetItemByPoint(e.Location))
            {
                tmci.OnMouseUp(sender, xe);
                if (xe.Trapped) break;
            }
        }

        void linkedList_MouseClick(object sender, MouseEventArgs e)
        {
            ChainedMouseEventArgs xe = ChainedMouseEventArgs.Factory(e);
            foreach (var tmci in GetItemByPoint(e.Location))
            {
                tmci.OnMouseClick(sender, xe);
                if (xe.Trapped) break;
            }
        }

        void linkedList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ChainedMouseEventArgs xe = ChainedMouseEventArgs.Factory(e);
            foreach (var tmci in GetItemByPoint(e.Location))
            {
                tmci.OnMouseDoubleClick(sender, xe);
                if (xe.Trapped) break;
            }
        }

        void linkedList_MouseMove(object sender, MouseEventArgs e)
        {
            ChainedMouseEventArgs xe = ChainedMouseEventArgs.Factory(e);
            foreach (var tmci in GetItemByPoint(e.Location))
            {
                if (!tmci.Equals(lastPointed))
                {
                    releaseLastPointed();
                    System.Diagnostics.Debug.WriteLine("point:" + tmci.GetType().ToString());
                    lastPointed = tmci;
                    if (tmci.Helptip != null)
                    {
                        toolTip.SetToolTip(linkedList, tmci.Helptip);
                        toolTip.Active = true;
                    }
                    tmci.OnMouseEnter(sender, xe);
                    return;
                }
                tmci.OnMouseMove(sender, xe);
                return;
            }
            releaseLastPointed();
        }

        void linkedList_MouseLeave(object sender, EventArgs e)
        {
            releaseLastPointed();
        }

        void linkedList_TimelineMouseControllableItemsUpdated(object sender, EventArgs e)
        {
            if (Core.FormManager.MainForm == null) return;
            if (Core.FormManager.MainForm.InvokeRequired)
                Core.FormManager.MainForm.Invoke(new Action(() => {
                    lock (itemsLocker)
                        Items = linkedList.MouseItems;
                }));
            else
                lock (itemsLocker)
                    Items = linkedList.MouseItems;
        }

        IEnumerable<TimelineMouseControllableItem> GetItemByPoint(Point location)
        {
            lock (itemsLocker)
                if (Items != null)
                    foreach (var item in Items)
                        if (item.ItemActualRect != null)
                            foreach (var rect in item.ItemActualRect)
                                if (isPointInnerRect(location, rect))
                                    yield return item;
            yield break;
        }

        bool isPointInnerRect(Point pt, Rectangle rect)
        {
            if (pt.X < rect.Left || pt.X > rect.Right ||
                pt.Y < rect.Top || pt.Y > rect.Bottom)
                return false;
            else
                return true;
        }

        void releaseLastPointed()
        {
            if(lastPointed != null)
            {
                lastPointed.OnMouseLeave(linkedList, new ChainedMouseEventArgs());
                lastPointed = null;
                toolTip.Active = false;
            }
        }

        public void Dispose()
        {
            toolTip.Dispose();
        }
    }
}
